/*
 * Copyright (c) 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 */
package net.sourceforge.perforce.ui.prefs;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sourceforge.perforce.ui.IPerforceUIConstants;
import net.sourceforge.perforce.ui.P4DecoratorConfiguration;
import net.sourceforge.perforce.ui.PerforceDecorator;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.internal.Policy;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.dialogs.ListSelectionDialog;

/**
  * @version $Revision: 66 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class P4DecoratorPreferencesPage
	extends FieldEditorPreferencePage 
	implements IWorkbenchPreferencePage
{
	// --------------------------------------------------------------------------- Private Variables
	
	/** Stores the Project / Example Text pair. */
	private TextPair projectTextPair;
	/** Stores the Folder / Example Text pair. */
	private TextPair folderTextPair;
	/** Stores the File / Example Text pair. */
	private TextPair fileTextPair; 
	/** Text control of dirty flag editor. */
	private Text dirty;
	
	// ------------------------------------------------------------------------- Public Constructors
	
	/** Constructor for P4DecoratorPreferencesPage. */
	public P4DecoratorPreferencesPage()
	{
		super(FieldEditorPreferencePage.GRID);
		setPreferenceStore(PerforceUIPlugin.getPlugin().getPreferenceStore());
	}
	 
	// ------------------------------------------------------------------------------ Public Methods
	
	/** @see IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) */
	public void init(IWorkbench workbench) 
	{
	}
	
	/** @see org.eclipse.jface.preference.IPreferencePage#performOk() */
	public boolean performOk() 
	{
		boolean result = super.performOk();
		PerforceDecorator.refresh();		
		
		return result;
	}

	// --------------------------------------------------------------------------- Protected Methods

	/** @see FieldEditorPreferencePage#createFieldEditors() */
	protected void createFieldEditors()
	{
		createFieldEditors(getFieldEditorParent());
	}
	
	/** @see FieldEditorPreferencePage#createFieldEditors() */
	protected void createFieldEditors(Composite parent) 
	{	
		Group textGroup = new Group(parent, SWT.NULL);
		GridLayout layout = new GridLayout();
		layout.numColumns = 3;
		textGroup.setLayout(layout);
		GridData data = new GridData(GridData.FILL_HORIZONTAL);		
		textGroup.setLayoutData(data);
		textGroup.setText(Policy.bind("P4DecoratorPreferencesPage.TextGroup"));        //$NON-NLS-1$
		
		createLabel(
			textGroup, Policy.bind("P4DecoratorPreferencesPage.TestGroupLabel"), 3);   //$NON-NLS-1$
		
		projectTextPair = createFormatEditorControl(
			textGroup, 
			IPerforceUIConstants.PREF_PROJECTTEXTFORMAT, 
			Policy.bind("P4DecoratorPreferencesPage.ProjectFormatLabel"),              //$NON-NLS-1$
			Policy.bind("P4DecoratorPreferencesPage.ProjectFormatButton"),             //$NON-NLS-1$
			getFolderBindingDescriptions());
		folderTextPair = createFormatEditorControl(
			textGroup, 
			IPerforceUIConstants.PREF_FOLDERTEXTFORMAT, 
			Policy.bind("P4DecoratorPreferencesPage.FolderFormatLabel"),               //$NON-NLS-1$ 
			Policy.bind("P4DecoratorPreferencesPage.FolderFormatButton"),              //$NON-NLS-1$
			getFolderBindingDescriptions());
		fileTextPair = createFormatEditorControl(
			textGroup, 
			IPerforceUIConstants.PREF_FILETEXTFORMAT, 
			Policy.bind("P4DecoratorPreferencesPage.FileFormatLabel"),                 //$NON-NLS-1$ 
			Policy.bind("P4DecoratorPreferencesPage.FileFormatButton"),                //$NON-NLS-1$
			getFileBindingDescriptions());
		
		StringFieldEditor outgoing =
			new InternalStringFieldEditor(
				IPerforceUIConstants.PREF_DIRTY_FLAG, 
				Policy.bind("P4DecoratorPreferencesPage.OutgoingLabel"),               //$NON-NLS-1$
				textGroup);
		outgoing.getTextControl(textGroup).addModifyListener(new ModifyListener() 
		{
			public void modifyText(ModifyEvent e) 
			{				
				updateExamples();
			}
		});
		addField(outgoing);
		dirty = outgoing.getTextControl(textGroup);
				
		StringFieldEditor added =
			new InternalStringFieldEditor(
				IPerforceUIConstants.PREF_ADDED_FLAG, 
				Policy.bind("P4DecoratorPreferencesPage.AddedLabel"),                  //$NON-NLS-1$
				textGroup);
		added.getTextControl(textGroup).addModifyListener(new ModifyListener() 
		{
			public void modifyText(ModifyEvent e) 
			{				
				updateExamples();
			}
		});
		addField(added);
		
		// TODO: Change message key
		BooleanFieldEditor showDirty = new BooleanFieldEditor(
			PerforceUIPlugin.CALCULATE_DIRTY_PREFERENCE,
			Policy.bind("PerforcePreferencePage.calculateDirty"),                      //$NON-NLS-1$
			getFieldEditorParent());
		addField(showDirty);
	}

	// ----------------------------------------------------------------------------- Private Methods

	/** Called to create a new format editor for the given preference. */
	private TextPair createFormatEditorControl(
		Composite parent, String prefName, String title, String buttonText, Map bindings)
	{
		FormatFieldEditor fieldEditor = 
			new FormatFieldEditor(prefName, title, buttonText, bindings, parent);
		fieldEditor.getTextControl(parent).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		fieldEditor.getTextControl(parent).addModifyListener(new ModifyListener() 
		{
			public void modifyText(ModifyEvent e) 
			{				
				updateExamples();
			}
		});
		addField(fieldEditor);
				
		createLabel(parent, Policy.bind("P4DecoratorPreferencesPage.ExampleLabel"), 1);//$NON-NLS-1$
		Text example = createText(parent, false);
		createLabel(parent, "", 1);                                                    //$NON-NLS-1$
		
		return new TextPair(fieldEditor.getTextControl(parent), example);
	}

	/** Crates a Text control.
	  *
	  * @param parent the control's parent.
	  * @param editable indicates whether the control is editable or not.
	  * @return the new Text control.  
	  */
	private Text createText(Composite parent, boolean editable) 
	{
		Text result = new Text(parent, SWT.BORDER);
		result.setEditable(editable);
		
		result.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		return result;
	}
	
	/** Creates a new Label control.
	  *
	  * @param parent the Label's parent control.
	  * @param text the text to display.
	  * @param span number of columns to span.
	  * @return the new Label control. 
	  */
	private Label createLabel(Composite parent, String text, int span) 
	{
		Label result = new Label(parent, SWT.LEFT);
		result.setText(text);
		
		GridData data = new GridData();
		data.horizontalSpan = span;
		data.horizontalAlignment = GridData.FILL;
		result.setLayoutData(data);
		
		return result;
	}

	/** Called to update the controls displaying the examples. */
	private void updateExamples() 
	{
		Map bindings = new HashMap();
		bindings.put(P4DecoratorConfiguration.P4PORT, "perforce:1666");                //$NON-NLS-1$
		bindings.put(P4DecoratorConfiguration.P4CLIENT, "acme-client");                //$NON-NLS-1$
		bindings.put(P4DecoratorConfiguration.P4USER, "username");                     //$NON-NLS-1$
		
		bindings.put(P4DecoratorConfiguration.HAVE_REV, "#3");                         //$NON-NLS-1$
		bindings.put(P4DecoratorConfiguration.HEAD_REV, "#4");                         //$NON-NLS-1$
		
		bindings.put(P4DecoratorConfiguration.DIRTY_FLAG, dirty.getText());

		bindings.put(P4DecoratorConfiguration.RESOURCE_NAME, "project");               //$NON-NLS-1$
		setProjectFormatExample(bindings);
		bindings.put(P4DecoratorConfiguration.RESOURCE_NAME, "folder");                //$NON-NLS-1$
		setFolderFormatExample(bindings);		
		bindings.put(P4DecoratorConfiguration.RESOURCE_NAME, "file.txt");              //$NON-NLS-1$
		setFileFormatExample(bindings);
	}

	/** Called to set the example for file format. 
	  *
	  * @param bindings contains the example bindings.
	  */
	private void setFileFormatExample(Map bindings) 
	{
		String example = 
			P4DecoratorConfiguration.bind(fileTextPair.getFormatControl().getText(), bindings);				
		fileTextPair.getExampleControl().setText(example);
	}

	/** Called to set the example for folder format. 
	  *
	  * @param bindings contains the example bindings.
	  */
	private void setFolderFormatExample(Map bindings) 
	{
		String example = 
			P4DecoratorConfiguration.bind(folderTextPair.getFormatControl().getText(), bindings);				
		folderTextPair.getExampleControl().setText(example);
	}

	/** Called to set the example for project format. 
	  *
	  * @param bindings contains the example bindings.
	  */
	private void setProjectFormatExample(Map bindings) 
	{
		String example = 
			P4DecoratorConfiguration.bind(projectTextPair.getFormatControl().getText(), bindings);				
		projectTextPair.getExampleControl().setText(example);
	}

	/** Returns descriptions for the valid file bindings.
	  *
	  * @return map with possible file bindings. 
	  */
	private Map getFileBindingDescriptions() 
	{
		Map bindings = new HashMap();
		bindings.put(
			P4DecoratorConfiguration.RESOURCE_NAME, 
			Policy.bind("P4DecoratorPreferencesPage.BindingResourceName"));            //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.HAVE_REV, 
			Policy.bind("P4DecoratorPreferencesPage.BindingHaveRevision"));            //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.HEAD_REV, 
			Policy.bind("P4DecoratorPreferencesPage.BindingHeadRevision"));            //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.DIRTY_FLAG, 
			Policy.bind("P4DecoratorPreferencesPage.BindingFileDirtyFlag"));           //$NON-NLS-1$
		return bindings;
	}
	
	/** Returns the descriptions of possible folder bindings.
	  *
	  * @return map containing the possible folder bindings. 
	  */
	private Map getFolderBindingDescriptions() 
	{
		Map bindings = new HashMap();
		bindings.put(
			P4DecoratorConfiguration.RESOURCE_NAME, 
			Policy.bind("P4DecoratorPreferencesPage.BindingResourceName"));            //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.P4PORT, 
			Policy.bind("P4DecoratorPreferencesPage.BindingP4port"));                  //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.P4CLIENT, 
			Policy.bind("P4DecoratorPreferencesPage.BindingP4client"));                //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.P4USER, 
			Policy.bind("P4DecoratorPreferencesPage.BindingP4user"));                  //$NON-NLS-1$
		bindings.put(
			P4DecoratorConfiguration.DIRTY_FLAG, 
			Policy.bind("P4DecoratorPreferencesPage.BindingFolderDirtyFlag"));         //$NON-NLS-1$
		return bindings;
	}

	// ---------------------------------------------------------------------- Private Nested Classes
	
	/** This class provides a "fixed" version of the StringFieldEditor. */
	private static class InternalStringFieldEditor extends StringFieldEditor
	{
		// --------------------------------------------------------------------- Public Constructors
		
		/** Constructor for InternalStringFieldEditor. */
		public InternalStringFieldEditor(String name, String labelText, Composite parent) 
		{
			super(name, labelText, parent);
		}
			
		// ----------------------------------------------------------------------- Protected Methods
		
		/** @see StringFieldEditor#createControl(Composite) */
		protected void createControl(Composite parent) 
		{
			GridLayout layout = (GridLayout) parent.getLayout();
			doFillIntoGrid(parent, layout.numColumns);
		}
	}
	
	/** This class is used to associate the format text fields with their example controls. */
	private static class TextPair
	{
		// ----------------------------------------------------------------------- Private Variables
		
		/** Stores a reference to the format control. */
		private Text formatControl;
		/** Stores a reference to the example control. */
		private Text exampleControl;
		
		// --------------------------------------------------------------------- Public Constructors
		
		/** Constructor for TextPair. */
		public TextPair(Text newFormatControl, Text newExampleControl)
		{
			formatControl = newFormatControl;
			exampleControl = newExampleControl;
		}
		
		// -------------------------------------------------------------------------- Public Methods
		
		/** Returns the format control.
		  *
		  * @return the format text control. 
		  */
		public Text getFormatControl()
		{
			return formatControl;
		}
		
		/** Returns the exmaple control.
		  *
		  * @return the example text control. 
		  */
		public Text getExampleControl()
		{
			return exampleControl;
		}
	}
}
